2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 Change History (most recent first):
27 $Log: Mac\040OS\040Test\040Searcher.c,v $
28 Revision 1.13 2003/08/14 02:19:54 cheshire
29 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
31 Revision 1.12 2003/08/12 19:56:24 cheshire
36 #include <stdio.h> // For printf()
37 #include <Events.h> // For WaitNextEvent()
38 #include <SIOUX.h> // For SIOUXHandleOneEvent()
40 #include "mDNSClientAPI.h" // Defines the interface to the client layer above
41 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
45 OTLIFO serviceinfolist
;
46 Boolean headerPrinted
;
50 typedef struct { ServiceInfo i
; mDNSBool add
; mDNSBool dom
; OTLink link
; } linkedServiceInfo
;
52 // These don't have to be globals, but their memory does need to remain valid for as
53 // long as the search is going on. They are declared as globals here for simplicity.
54 #define RR_CACHE_SIZE 1000
55 static CacheRecord rrcachestorage
[RR_CACHE_SIZE
];
56 static mDNS mDNSStorage
;
57 static mDNS_PlatformSupport PlatformSupportStorage
;
58 static SearcherServices services
;
59 static DNSQuestion browsequestion
, domainquestion
;
61 // PrintServiceInfo prints the service information to standard out
62 // A real application might want to do something else with the information
63 static void PrintServiceInfo(SearcherServices
*services
)
65 OTLink
*link
= OTReverseList(OTLIFOStealList(&services
->serviceinfolist
));
69 linkedServiceInfo
*ls
= OTGetLinkObject(link
, linkedServiceInfo
, link
);
70 ServiceInfo
*s
= &ls
->i
;
72 if (!services
->headerPrinted
)
74 printf("%-55s Type Domain IP Address Port Info\n", "Name");
75 services
->headerPrinted
= true;
81 ConvertDomainNameToCString(&s
->name
, c_dom
);
82 if (ls
->add
) printf("%-55s available for browsing\n", c_dom
);
83 else printf("%-55s no longer available for browsing\n", c_dom
);
88 domainname type
, domain
;
89 UInt16 port
= (UInt16
)((UInt16
)s
->port
.b
[0] << 8 | s
->port
.b
[1]);
90 char c_name
[64], c_type
[256], c_dom
[256], c_ip
[20];
92 DeconstructServiceName(&s
->name
, &name
, &type
, &domain
);
93 ConvertDomainLabelToCString_unescaped(&name
, c_name
);
94 ConvertDomainNameToCString(&type
, c_type
);
95 ConvertDomainNameToCString(&domain
, c_dom
);
96 sprintf(c_ip
, "%d.%d.%d.%d", s
->ip
.ip
.v4
.b
[0], s
->ip
.ip
.v4
.b
[1], s
->ip
.ip
.v4
.b
[2], s
->ip
.ip
.v4
.b
[3]);
98 printf("%-55s %-16s %-14s ", c_name
, c_type
, c_dom
);
99 if (ls
->add
) printf("%-15s %5d %#s\n", c_ip
, port
, s
->TXTinfo
);
100 else printf("Removed\n");
108 // When the name, address, port, and txtinfo for a service is found, FoundInstanceInfo()
109 // enqueues a record for PrintServiceInfo() to print.
110 // Note, a browsing application would *not* normally need to get all this information --
111 // all it needs is the name, to display to the user.
112 // Finding out the address, port, and txtinfo should be deferred to the time that the user
113 // actually needs to contact the service to use it.
114 static void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
116 SearcherServices
*services
= (SearcherServices
*)query
->ServiceInfoQueryContext
;
117 linkedServiceInfo
*info
= (linkedServiceInfo
*)(query
->info
);
118 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
120 mDNS_StopResolveService(m
, query
); // For this test code, one answer is sufficient
121 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
126 // When a new named instance of a service is found, FoundInstance() is called.
127 // In this sample code we turn around and immediately issue a query to resolve that service name to
128 // find its address, port, and txtinfo, but a normal browing application would just display the name.
129 static void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
131 #pragma unused (question)
132 SearcherServices
*services
= (SearcherServices
*)question
->QuestionContext
;
133 linkedServiceInfo
*info
;
135 debugf("FoundInstance %##s PTR %##s", answer
->name
.c
, answer
->rdata
->u
.name
.c
);
137 if (answer
->rrtype
!= kDNSType_PTR
) return;
138 if (!services
) { debugf("FoundInstance: services is NULL"); return; }
140 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
141 if (!info
) { services
->lostRecords
= true; return; }
143 info
->i
.name
= answer
->rdata
->u
.name
;
144 info
->i
.InterfaceID
= answer
->InterfaceID
;
145 info
->i
.ip
.type
= mDNSAddrType_IPv4
;
146 info
->i
.ip
.ip
.v4
= zeroIPAddr
;
147 info
->i
.port
= zeroIPPort
;
148 info
->add
= AddRecord
;
149 info
->dom
= mDNSfalse
;
151 if (!AddRecord
) // If TTL == 0 we're deleting a service,
152 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
153 else // else we're adding a new service
155 ServiceInfoQuery
*q
= (ServiceInfoQuery
*)OTAllocMem(sizeof(ServiceInfoQuery
));
156 if (!q
) { OTFreeMem(info
); services
->lostRecords
= true; return; }
157 mDNS_StartResolveService(m
, q
, &info
->i
, FoundInstanceInfo
, services
);
161 static void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
164 #pragma unused (question)
165 SearcherServices
*services
= (SearcherServices
*)question
->QuestionContext
;
166 linkedServiceInfo
*info
;
168 debugf("FoundDomain %##s PTR %##s", answer
->name
.c
, answer
->rdata
->u
.name
.c
);
170 if (answer
->rrtype
!= kDNSType_PTR
) return;
171 if (!services
) { debugf("FoundDomain: services is NULL"); return; }
173 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
174 if (!info
) { services
->lostRecords
= true; return; }
176 info
->i
.name
= answer
->rdata
->u
.name
;
177 info
->i
.InterfaceID
= answer
->InterfaceID
;
178 info
->i
.ip
.type
= mDNSAddrType_IPv4
;
179 info
->i
.ip
.ip
.v4
= zeroIPAddr
;
180 info
->i
.port
= zeroIPPort
;
181 info
->add
= AddRecord
;
182 info
->dom
= mDNStrue
;
184 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
187 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
188 static Boolean
YieldSomeTime(UInt32 milliseconds
)
190 extern Boolean SIOUXQuitting
;
192 WaitNextEvent(everyEvent
, &e
, milliseconds
/ 17, NULL
);
193 SIOUXHandleOneEvent(&e
);
194 return(SIOUXQuitting
);
199 extern void mDNSPlatformIdle(mDNS
*const m
); // Only needed for debugging version
201 Boolean DoneSetup
= false;
203 SIOUXSettings
.asktosaveonclose
= false;
204 SIOUXSettings
.userwindowtitle
= "\pMulticast DNS Searcher";
205 SIOUXSettings
.rows
= 40;
206 SIOUXSettings
.columns
= 132;
208 printf("Prototype Multicast DNS Searcher\n\n");
209 printf("WARNING! This is experimental software.\n\n");
210 printf("Multicast DNS is currently an experimental protocol.\n\n");
211 printf("This software reports errors using MacsBug breaks,\n");
212 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
213 printf("******************************************************************************\n");
215 err
= InitOpenTransport();
216 if (err
) { debugf("InitOpenTransport failed %d", err
); return(err
); }
218 err
= mDNS_Init(&mDNSStorage
, &PlatformSupportStorage
, rrcachestorage
, RR_CACHE_SIZE
,
219 mDNS_Init_DontAdvertiseLocalAddresses
, mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
220 if (err
) return(err
);
222 services
.serviceinfolist
.fHead
= NULL
;
223 services
.headerPrinted
= false;
224 services
.lostRecords
= false;
226 while (!YieldSomeTime(35))
228 // For debugging, use "#define __ONLYSYSTEMTASK__ 1" and call mDNSPlatformIdle() periodically.
229 // For shipping code, don't define __ONLYSYSTEMTASK__, and you don't need to call mDNSPlatformIdle()
230 mDNSPlatformIdle(&mDNSStorage
); // Only needed for debugging version
231 if (mDNSStorage
.mDNSPlatformStatus
== mStatus_NoError
&& !DoneSetup
)
233 domainname srvtype
, srvdom
;
235 printf("\nSending mDNS service lookup queries and waiting for responses...\n\n");
236 MakeDomainNameFromDNSNameString(&srvtype
, "_http._tcp.");
237 MakeDomainNameFromDNSNameString(&srvdom
, "local.");
238 err
= mDNS_StartBrowse(&mDNSStorage
, &browsequestion
, &srvtype
, &srvdom
, mDNSInterface_Any
, FoundInstance
, &services
);
240 err
= mDNS_GetDomains(&mDNSStorage
, &domainquestion
, mDNS_DomainTypeBrowse
, mDNSInterface_Any
, FoundDomain
, &services
);
244 if (services
.serviceinfolist
.fHead
)
245 PrintServiceInfo(&services
);
247 if (services
.lostRecords
)
249 services
.lostRecords
= false;
250 printf("**** Warning: Out of memory: Records have been missed.\n");
254 mDNS_StopBrowse(&mDNSStorage
, &browsequestion
);
255 mDNS_Close(&mDNSStorage
);